package org.totoro.memory.oom;

/**
 * JVM 线程栈存储了方法的执行过程、基本数据类型、局部变量、对象指针和返回值等信息，这些都需
 * 要消耗内存。一旦线程栈的大小增长超过了允许的内存限制，就会抛出
 * java.lang.StackOverflowError 错误。
 * <p>
 * 引发 StackOverFlowError 的常见原因有以下几种：
 * <p>
 * 无限递归循环调用（最常见）。
 * 执行了大量方法，导致线程栈空间耗尽。
 * 方法内声明了海量的局部变量。
 * native 代码有栈上分配的逻辑，并且要求的内存还不小，比如 java.net.SocketInputStream.read0 会在栈上要求分配一个 64KB 的缓存（64位 Linux）。
 * 除了程序抛出 StackOverflowError 错误以外，还有两种定位栈溢出的方法：
 * <p>
 * 进程突然消失，但是留下了 crash 日志，可以检查 crash 日志里当前线程的 stack 范围，以及 RSP 寄存器的值。如果 RSP 寄存器的值超出这个 stack 范围，那就说明是栈溢出了。
 * 如果没有 crash 日志，那只能通过 coredump 进行分析。在进程运行前，先执行 ulimit -c unlimited，当进程挂掉之后，会产生一个 core.[pid] 的文件，然后再通过 jstack $JAVA_HOME/bin/java core.[pid] 来看输出的栈。如果正常输出了，那就可以看是否存在很长的调用栈的线程，当然还有可能没有正常输出的，因为 jstack 的这条从 core 文件抓栈的命令其实是基于 Serviceability Agent 实现的，而 SA 在某些版本里有 Bug。
 * 常见的解决方法包括以下几种：
 * <p>
 * 修复引发无限递归调用的异常代码， 通过程序抛出的异常堆栈，找出不断重复的代码行，按图索骥，修复无限递归 Bug。
 * 排查是否存在类之间的循环依赖。
 * 排查是否存在在一个类中对当前类进行实例化，并作为该类的实例变量。
 * 通过 JVM 启动参数 -Xss 增加线程栈内存空间， 某些正常使用场景需要执行大量方法或包含大量局部变量，这时可以适当地提高线程栈空间限制，例如通过配置 -Xss2m 将线程栈空间调整为 2 mb。
 *
 * @author daocr
 * @date 2020/3/2
 */
public class StackOverflowErrorOom {
}
